﻿// =============================================================================
// XPathDebugger And Examples PerformanceTests.cs
// Copyright (c) 2013 TNTTechnologies Inc.
// =============================================================================

#region

using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Windows.Controls;
using System.Xml;
using System.Xml.Serialization;

using Example;

using TNTTools;
using TNTTools.Reflection;
using TNTTools.Serialization;

#endregion

namespace XPathDebugger.CashFlowReports_Example{
    public class PerformanceTests{
        /// <summary>
        ///     Serialization Example - Simple objects
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public static void SerializationPerformance(ListBox listbox){
            listbox.Items.Add("\r\nSerialization Performance");
            // Here we wil use a relatively complex object structure as an example of features,
            // but any object will do!

            IPodConnector connector = new IPodConnector(){ Version = "1.1a" };
            Screen screen = new Screen(){ Size = "4 inch" };
            Stereo stereo = new Stereo(){ Make = "alpine", Watts = "1000", };
            Car mycar = new Car(){ brake = "5 piston", wheel = "22", Stereo = stereo, IPodConnector = connector };
            const int testCount = 10;

            Stopwatch watch = Stopwatch.StartNew();
            // Basic serialization example, raw with no attributes.
            Car entityFromXml = null;
            for (int i = 0; i < testCount; ++i){
                entityFromXml = SerializerFacade.Deserialize<Car>(SerializerFacade.SerializeBasic(mycar).ToString());
                watch.Stop();
            }
            listbox.Items.Add("\tRound trip serialization using TNT Ticks=" + watch.ElapsedTicks);

            Stopwatch watchNetXml = Stopwatch.StartNew();
            Car fromNetXML = null;
            for (int i = 0; i < testCount; ++i){
                StringWriter stringWriter = new StringWriter();
                XmlSerializer xmlSerializer = new XmlSerializer(typeof(Car));
                xmlSerializer.Serialize(stringWriter, mycar);
                fromNetXML = DeserializeWithNet<Car>(stringWriter.ToString());
            }
            watchNetXml.Stop();
            listbox.Items.Add("\tRound trip serialization using .Net Ticks=" + watchNetXml.ElapsedTicks);
        }

        /// <summary>
        ///     Serialization Example - Simple objects
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public static void ReflectionPerformanceOfSetter(ListBox listbox){
            listbox.Items.Add("\r\nReflection Performance Of Setter");

            // Here we wil use a relatively complex object structure as an example of features,

            IPodConnector connector = new IPodConnector(){ Version = "1.1a" };
            Screen screen = new Screen(){ Size = "4 inch" };
            Stereo stereo = new Stereo(){ Make = "alpine", Watts = "1000", };
            Car mycar = new Car(){ brake = "5 piston", wheel = "22", Stereo = stereo, IPodConnector = connector };

            ReflectionPropertyCache cache = new ReflectionPropertyCache();
            ObjectInfo carInfo = cache.GetCachedObjectInfo(mycar, mycar.GetType());

            // Let's set a property manually, and see how long that takes.
            Stopwatch watch = new Stopwatch();
            const int testLength = 1000;

            GC.Collect();

            watch = Stopwatch.StartNew();
            for (int i = 0; i < testLength; ++i){
                mycar.FactoryDate = DateTime.Now;
            }
            watch.Stop();
            long ticks = watch.ElapsedTicks;

            // Now use the TNT reflection to set this puppy.
            watch = Stopwatch.StartNew();
            for (int i = 0; i < testLength; ++i){
                carInfo.propertyInfo[0].setter.dateTimeSetter(mycar, DateTime.Now);
            }
            watch.Stop();
            long ticksTest2 = watch.ElapsedTicks;
            long DifferenceBetweenTNTAndActuallySettingAProperty = ticksTest2 - ticks;

            // Now use the old way of reflection to set it, we will count the cost of generating reflection info
            watch = Stopwatch.StartNew();
            PropertyInfo[] propInfo = mycar.GetType().GetProperties();
            for (int i = 0; i < testLength; ++i){
                propInfo[0].SetValue(mycar, DateTime.Now, null); // note datetime struct is boxed.
            }
            watch.Stop();
            long ticksTest3 = watch.ElapsedTicks;

            // Now use the old way of reflection to set it, we will NOT count the cost of generating reflection info
            // only count how long it takes to  just set the property
            watch = Stopwatch.StartNew();
            for (int i = 0; i < testLength; ++i){
                propInfo[0].SetValue(mycar, DateTime.Now, null); // note datetime struct is boxed.
            }
            watch.Stop();
            long ticksTest4 = watch.ElapsedTicks;

            listbox.Items.Add(
                "\tDifference between setting a property directy and using TNT reflection Ticks:"
                + DifferenceBetweenTNTAndActuallySettingAProperty);
            listbox.Items.Add(
                "\tTNT Reflection is faster at setting a property than .Net by Ticks:" + (ticksTest3 - ticksTest2));
        }

        /// <summary>
        ///     Serialization Example - Simple objects
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public static void ReflectionPerformanceOfGetter(ListBox listbox){
            listbox.Items.Add("\r\nReflection Performance Of Getter");
            // Here we wil use a relatively complex object structure as an example of features,

            IPodConnector connector = new IPodConnector(){ Version = "1.1a" };
            Screen screen = new Screen(){ Size = "4 inch" };
            Stereo stereo = new Stereo(){ Make = "alpine", Watts = "1000", };
            Car mycar = new Car(){ brake = "5 piston", wheel = "22", Stereo = stereo, IPodConnector = connector };

            ReflectionPropertyCache cache = new ReflectionPropertyCache();
            ObjectInfo carInfo = cache.GetCachedObjectInfo(mycar, mycar.GetType());

            // Let's set a property manually, and see how long that takes.
            Stopwatch watch = new Stopwatch();
            const int testLength = 1000;

            GC.Collect();
            DateTime time;

            watch = Stopwatch.StartNew();
            for (int i = 0; i < testLength; ++i){
                time = mycar.FactoryDate;
            }
            watch.Stop();
            long ticks = watch.ElapsedTicks;

            // Now use the TNT reflection to set this puppy.
            watch = Stopwatch.StartNew();
            for (int i = 0; i < testLength; ++i){
                time = carInfo.propertyInfo[0].getter.dateTimeGetter(mycar);
            }
            watch.Stop();
            long ticksTest2 = watch.ElapsedTicks;
            long DifferenceBetweenTNTAndActuallyGettingAProperty = ticksTest2 - ticks;

            // Now use the old way of reflection to get it, we will count the cost of generating reflection info
            // only count how long it takes to  just set the property
            watch = Stopwatch.StartNew();
            PropertyInfo[] propInfo = mycar.GetType().GetProperties();
            for (int i = 0; i < testLength; ++i){
                time = (DateTime)propInfo[0].GetValue(mycar, null);
            }
            watch.Stop();
            long ticksTest3 = watch.ElapsedTicks;

            listbox.Items.Add(
                "\tDifference between getting a property directy and using TNT reflection Ticks:"
                + DifferenceBetweenTNTAndActuallyGettingAProperty);
            listbox.Items.Add(
                "\tTNT Reflection is faster at getting a property than .Net by Ticks:" + (ticksTest3 - ticksTest2));
        }

        /// <summary>
        ///     .Net deserializer
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="xml"></param>
        /// <returns></returns>
        public static T DeserializeWithNet<T>(string xml){
            if (string.IsNullOrEmpty(xml)){
                return default(T);
            }

            XmlSerializer serializer = new XmlSerializer(typeof(T));

            XmlReaderSettings settings = new XmlReaderSettings();
            // No settings need modifying here 

            using (StringReader textReader = new StringReader(xml)){
                using (XmlReader xmlReader = XmlReader.Create(textReader, settings)){
                    return (T)serializer.Deserialize(xmlReader);
                }
            }
        }
    }
}